Helper.using('py.Actions', function (ns) {

    var Figures = py.Figures;

    // vừa draw vừa select
    ns.DrawPoint = function (drawingPad) {
        ns.DrawAction.apply(this, [drawingPad]);

        var action = this,
            stage = drawingPad.stage(),
            trap, selector,
            point = new Figures.PointXY, visual = point.visual(),
            layer = drawingPad.previewLayer(),
            _super = {
                stop:this.stop
            };


        function preview() {
            var position = stage.getMousePosition(),
                viewPort = drawingPad.viewPort(),
                unit = viewPort.getGeoPoint(position);

            point.setX(unit.x);
            point.setY(unit.y);
            visual.setPosition(position);
            action.invokePreview({figure:point});
            layer.draw();
        }

        function finish() {
            var position = stage.getMousePosition(),
                viewPort = drawingPad.viewPort(),
                unit = viewPort.getGeoPoint(position);


            point.setX(unit.x);
            point.setY(unit.y);
            action.invokeFinish({figure:point, selected:[point]});
        }

        function hover(figure, on) {
            if (on) {
                figure.addShadow();
                visual.hide();
                action.invokePreview({figure:figure});
            } else {
                figure.removeShadow();
                visual.show();
            }
            layer.draw();
        }

        function select() {
            hover(this, false);
            action.invokeFinish({selected:[this]});
        }

        this.startFunc = function () {
            layer.add(visual);
            trap = drawingPad.getCapture();
            selector = drawingPad.getSelector('isPoint');

            visual.on('mousemove.drawPoint', preview);
            visual.on('click.drawPoint', finish);
            trap.on('mousemove', preview).on('click', finish).start();
            selector.on('mouseover',
                function () {
                    hover(this, true);
                }).on('mouseout',
                function () {
                    hover(this, false)
                }).on('click', select);

            selector.start();
        };

        this.stop = function () {
            // chi stop khi co the
            visual.off('mousemove.drawPoint click.drawPoint');
            trap && trap.stop && trap.stop();
            selector && selector.stop && selector.stop();
            _super.stop();
        }
    };

    var DrawActionFactory = function (params) {
        /*
         {
         result:'Circle2Point',
         steps:[
         {'type':'Point', setter:'setCenter'},
         {'type':'Point', setter:'setPoint'}
         ]
         }
         */
        var total = params.steps.length;

        if (total < 2) {
            throw new Error('Need at least 2 child actions');
        }


        return function (drawingPad) {
            ns.DrawAction.call(this, drawingPad);

            var action = this,
                selects = [], selected = [],
                result = new Figures[params.result],
                layer = action.previewLayer(),
                visual = result.visual(),
                _super = {
                    stop:this.stop
                }


            this.startFunc = function () {
                // init selector
                params.steps.forEach(function (step, index) {
                    var select = ns.SelectAction.byType(drawingPad, step.type),
                        setter;

                    if (typeof step.setter === 'string') {
                        setter = result[step.setter];
                    } else if (Helper.isFunction(step.setter)) {
                        setter = function () {
                            step.setter.apply(result, arguments);
                        }
                    }

                    if (!setter) {
                        throw new Error(['cannot find method ', step.setter, ' of ', result]);
                    }

                    // nếu chưa phải là cái cuối
                    if (total - 1 > index) {
                        select.on('finished', function (event) {
                            var figure = event.selected[0];

                            if(!figure || Helper.inArray(figure, selected)) {
                                select.start();
                                return;
                            }

                            setter(figure);
                            select.stop();
                            selects[index + 1].start();

                            // step sau là step preview thì add visual vào layer
                            if (index == total - 2) {
                                layer.add(visual);
                            }
                        });
                    } else {
                        // last step
                        select.on('preview',
                            function (event) {
                                var figure = event.figure;

                                if(!figure || Helper.inArray(figure, selected)) {
                                    select.start();
                                    return;
                                }

                                setter(figure);
                                result.update(drawingPad.viewPort());
                                action.invokePreview({figure:result});
                                layer.draw();
                            }).on('finished', function (event) {
                                var figure = event.selected[0];

                                if(!figure || Helper.inArray(figure, selected)) {
                                    select.start();
                                    return;
                                }

                                setter(figure);
                                action.invokeFinish({figure:result});
                            });
                    }

                    selects.push(select);
                });

                // start cái đầu tiên
                selects[0].start();
            };

            this.stop = function () {
                selects.forEach(function (select) {
                    select.stop();
                });
                _super.stop();
            };
        };
    };

    var actions = [
        {
            result:'MidPoint',
            steps:[
                {'type':'Point', setter: function(point) {this.setEnd(0, point)}},
                {'type':'Point', setter: function(point) {this.setEnd(1, point)}}
            ]
        },{
            result:'Circle2Point',
            steps:[
                {'type':'Point', setter:'setCenter'},
                {'type':'Point', setter:'setPoint'}
            ]
        },
        {
            result: 'Segment2Point',
            steps : [
                {type: 'Point', setter : function(point) { this.setPoint(0, point); }},
                {type: 'Point', setter : function(point) { this.setPoint(1, point); }}
            ]
        },
        {
            result: 'Circle3Point',
            steps : [
                {type: 'Point', setter : function(point) { this.setPoint(0, point); }},
                {type: 'Point', setter : function(point) { this.setPoint(1, point); }},
                {type: 'Point', setter : function(point) { this.setPoint(2, point); }}
            ]
        },
        {
            result: 'Line2Point',
            steps : [
                {type: 'Point', setter : function(point) { this.setPoint(0, point); }},
                {type: 'Point', setter : function(point) { this.setPoint(1, point); }}
            ]
        },
        {
            result: 'ParallelLine',
            steps: [
                {type: 'LinearObject', setter: 'setLinear'},
                {type: 'Point', setter: 'setAnchor'}
            ]
        },
        {
            result: 'Ellipse3Point',
            steps : [
                {type: 'Point', setter : function(point) { this.setFocus(0, point); }},
                {type: 'Point', setter : function(point) { this.setFocus(1, point); }},
                {type: 'Point', setter : function(point) { this.setPoint(point); }}
            ]
        },
        {
            result: 'SemiCircle',
            steps : [
                {type: 'Point', setter : function(point) { this.setPoint(0,point); }},
                {type: 'Point', setter : function(point) { this.setPoint(1,point); }}
            ]
        },
        {
            result: 'CircularArc',
            steps : [
                {type: 'Point', setter : function(point) { this.setCenter(point); }},
                {type: 'Point', setter : function(point) { this.setOnCircle(point); }},
                {type: 'Point', setter : function(point) { this.setPoint(point); }}
            ]
        }
    ];

    actions.forEach(function(actionData) {
        ns['Draw' + actionData.result] = DrawActionFactory(actionData);
    })

});